home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / rpc / rpcServer.c < prev    next >
C/C++ Source or Header  |  1991-07-29  |  41KB  |  1,397 lines

  1. /*
  2.  * rpcServer.c --
  3.  *
  4.  *      This is the top level code for an RPC server process, plus the
  5.  *      server-side dispatch routine with which the server process must
  6.  *      synchronize.  sA server process does some initialization and then
  7.  *      goes into a service loop receiving request messages and invoking
  8.  *      service stubs.  This file also has utilities for sending replies
  9.  *      and acks.
  10.  *
  11.  * Copyright (C) 1985 Regents of the University of California
  12.  * All rights reserved.
  13.  */
  14.  
  15. #ifndef lint
  16. static char rcsid[] = "$Header: /sprite/src/kernel/rpc/RCS/rpcServer.c,v 9.22 91/05/06 14:43:21 kupfer Exp $ SPRITE (Berkeley)";
  17. #endif /* not lint */
  18.  
  19.  
  20. #include <sprite.h>
  21. #include <stdio.h>
  22. #include <bstring.h>
  23. #include <rpc.h>
  24. #include <rpcInt.h>
  25. #include <rpcServer.h>
  26. #include <rpcTrace.h>
  27. #include <rpcHistogram.h>
  28. #include <net.h>
  29. #include <proc.h>
  30. #include <dbg.h>
  31. #include <stdlib.h>
  32. #include <recov.h>
  33.  
  34. /*
  35.  * An on/off switch for the service side of the RPC system.  Hosts do not
  36.  * initially respond to RPC requests so they can configure themselves
  37.  * as needed at boot time.  This means we are dependent on a user program
  38.  * to execute and turn on this flag.
  39.  */
  40. Boolean rpcServiceEnabled = FALSE;
  41.  
  42. /*
  43.  * The server state table.  It has a maximum size which constrains the
  44.  * number of server processes that can be created.  The number of free
  45.  * servers is maintained, as well as the total number of created servers.
  46.  */
  47. RpcServerState **rpcServerPtrPtr = (RpcServerState **)NIL;
  48. int        rpcAbsoluteMaxServers = 70;
  49. int        rpcMaxServers = 50;
  50. int        rpcNumServers = 0;
  51.  
  52. /*
  53.  * rpcMaxServerAge is the number of times the Rpc_Daemon will send
  54.  * a probe message to a client (without response) before forcibly
  55.  * reclaiming the server process for use by other clients.  A probe
  56.  * message gets sent each time the daemon wakes up and finds the
  57.  * server process still idle awaiting a new request from the client.
  58.  */
  59. int rpcMaxServerAge = 10;    /* For testing set to 1. Was 10. */
  60.  
  61. /*
  62.  * A histogram is kept of service time.  This is available to user
  63.  * programs via the Sys_Stats SYS_RPC_SERVER_HIST command.  The on/off
  64.  * flags is settable via Fs_Command FS_SET_RPC_SERVER_HIST
  65.  */
  66. Rpc_Histogram *rpcServiceTime[RPC_LAST_COMMAND+1];
  67. Boolean rpcServiceTiming = FALSE;
  68.  
  69. /*
  70.  * A raw count of the number of service calls.
  71.  */
  72. int rpcServiceCount[RPC_LAST_COMMAND+1];
  73.  
  74. /*
  75.  * Buffers for sending negative acknowledgements.
  76.  */
  77. NackData    rpcNack;
  78. /*
  79.  * Whether or not to send negative acknowledgements.
  80.  */
  81. Boolean        rpcSendNegAcks = FALSE;
  82. /*
  83.  * Number of nack buffers in system.
  84.  */
  85. int    rpc_NumNackBuffers = 4;
  86. /*
  87.  * To tell if we've already initialized the correct number of nack buffers
  88.  * when the rpc system is turned on.  This variable equals the number of
  89.  * nack buffers last initialized.
  90.  */
  91. int    oldNumNackBuffers = 0;
  92.  
  93.  
  94. /*
  95.  * For tracing the behavior of the rpc servers.
  96.  */
  97. typedef struct    RpcServerStateInfo {
  98.     int        index;
  99.     int        clientID;
  100.     int        channel;
  101.     int        state;
  102.     int        num;
  103.     Timer_Ticks    time;
  104. } RpcServerStateInfo;
  105.  
  106. typedef    struct    RpcServerTraces {
  107.     RpcServerStateInfo    *traces;
  108.     int            traceIndex;
  109.     Boolean        okay;
  110.     Boolean        error;
  111.     Sync_Semaphore    mutex;
  112. } RpcServerTraces;
  113.  
  114. RpcServerTraces    rpcServerTraces = {(RpcServerStateInfo *) NIL, 0,  FALSE,
  115.                 FALSE, Sync_SemInitStatic("rpcServerTraces")};
  116.  
  117. /*
  118.  * Try 1 Meg of traces.
  119.  */
  120. #define RPC_NUM_TRACES (0x100000 / sizeof (RpcServerStateInfo))
  121.  
  122. static void NegAckFunc _ARGS_((ClientData clientData, Proc_CallInfo *callInfoPtr));
  123.  
  124.  
  125.  
  126.  
  127. /*
  128.  *----------------------------------------------------------------------
  129.  *
  130.  * Rpc_Server --
  131.  *
  132.  *      The top level procedure of an RPC server process.  This
  133.  *      synchronizes with RpcServerDispatch while it waits for new
  134.  *      requests to service.  It assumes that its buffers contain a new
  135.  *      request when its SRV_BUSY state bit is set.  It clears this bit
  136.  *      and sets the SRV_WAITING bit after it completes the service
  137.  *      procedure and returns a reply to the client.
  138.  *
  139.  * Results:
  140.  *    This procedure never returns.
  141.  *
  142.  * Side effects:
  143.  *    The server process attaches itself to a slot in the
  144.  *    table of server states.  Some statistics are taken at this level.
  145.  *
  146.  *----------------------------------------------------------------------
  147.  */
  148. void
  149. Rpc_Server()
  150. {
  151.     register RpcServerState *srvPtr;    /* This server's state */
  152.     register RpcHdr *rpcHdrPtr;        /* Its request message header */
  153.     register int command;        /* Identifies the service procedure */
  154.     register ReturnStatus error;    /* Return error code */
  155.     Rpc_Storage storage;        /* Specifies storage of request and
  156.                      * reply buffers passed into the stubs*/
  157.     Proc_ControlBlock *procPtr;        /* our process information */
  158.  
  159.     procPtr = Proc_GetCurrentProc();
  160.  
  161.     srvPtr = RpcServerInstall();
  162.     if (srvPtr == (RpcServerState *)NIL) {
  163.     printf("RPC server can't install itself.\n");
  164.     Proc_Exit((int) RPC_INTERNAL_ERROR);
  165.     }
  166.     error = SUCCESS;
  167.     for ( ; ; ) {
  168.     /*
  169.      * Synchronize with RpcServerDispatch and await a request message.
  170.      * Change our state to indicate that we are ready for input.
  171.      */
  172.     MASTER_LOCK(&srvPtr->mutex);
  173.     srvPtr->state &= ~(SRV_BUSY|SRV_STUCK);
  174.     srvPtr->state |= SRV_WAITING;
  175.     if (error == RPC_NO_REPLY) {
  176.         srvPtr->state |= SRV_NO_REPLY;
  177.     }
  178.     while ((srvPtr->state & SRV_BUSY) == 0) {
  179.         Sync_MasterWait(&srvPtr->waitCondition,
  180.                 &srvPtr->mutex, TRUE);
  181.         if (sys_ShuttingDown) {
  182.         srvPtr->state = SRV_NOTREADY;
  183.         MASTER_UNLOCK(&srvPtr->mutex);
  184.         Proc_Exit(0);
  185.         }
  186.     }
  187.     srvPtr->state &= ~SRV_NO_REPLY;
  188.     MASTER_UNLOCK(&srvPtr->mutex);
  189.  
  190.     /*
  191.      * At this point there is unsynchronized access to
  192.      * the server state.  We are marked BUSY, however, and
  193.      * RpcServerDispatch knows this and doesn't muck accordingly.
  194.      */
  195.  
  196.     /*
  197.      * Free up our previous reply.  The freeReplyProc is set by the
  198.      * call to Rpc_Reply.
  199.      */
  200. #ifndef lint
  201.     /* Won't lint due to cast of function ptr to address. */
  202.     if ((Address)srvPtr->freeReplyProc != (Address)NIL) {
  203.         (void)(*srvPtr->freeReplyProc)(srvPtr->freeReplyData);
  204.         srvPtr->freeReplyProc = (int (*)())NIL;
  205.     }
  206. #endif /* lint */
  207.  
  208.     rpcHdrPtr = &srvPtr->requestRpcHdr;
  209. #ifdef TIMESTAMP
  210.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_A, " input");
  211. #endif /* TIMESTAMP */
  212.     /*
  213.      * Monitor message traffic to keep track of other hosts.  This call
  214.      * has a side effect of blocking the server process while any
  215.      * crash recovery call-backs are in progress.
  216.      */
  217. #ifndef NO_RECOVERY
  218.     Recov_HostAlive(srvPtr->clientID, rpcHdrPtr->bootID,
  219.             FALSE, (Boolean) (rpcHdrPtr->flags & RPC_NOT_ACTIVE));
  220. #endif
  221.     /*
  222.      * Before branching to the service procedure we check that the
  223.      * server side of RPC is on, and that the RPC number is good.
  224.      * The "disabled service" return code is understood by other
  225.      * hosts to mean that we are still alive, but are not yet
  226.      * ready to be a server - ie. we are still checking disks etc.
  227.      */
  228.     command = rpcHdrPtr->command;
  229.     if (!rpcServiceEnabled) {
  230.         /*
  231.          * Silently ignore broadcast requests.  If we return an error
  232.          * we'll cause the sender to stop pre-maturely.  Otherwise
  233.          * return an indication that our service is not yet ready.
  234.          */
  235.         if (rpcHdrPtr->serverID == RPC_BROADCAST_SERVER_ID) {
  236.         error = RPC_NO_REPLY;
  237.         } else {
  238.         error = RPC_SERVICE_DISABLED;
  239.         }
  240.     } else if (command <= 0 || command > RPC_LAST_COMMAND) {
  241.         error = RPC_INVALID_RPC;
  242.     } else {
  243.         Time histTime;
  244.  
  245.         rpcServiceCount[command]++;
  246.  
  247.         if (procPtr->locksHeld != 0) {
  248.         panic("Starting RPC with locks held.\n");
  249.         }
  250.  
  251.         RPC_SERVICE_TIMING_START(command, &histTime);
  252.  
  253.         storage.requestParamPtr    = srvPtr->request.paramBuffer.bufAddr;
  254.         storage.requestParamSize    = srvPtr->actualParamSize;
  255.         storage.requestDataPtr    = srvPtr->request.dataBuffer.bufAddr;
  256.         storage.requestDataSize    = srvPtr->actualDataSize;
  257.         storage.replyParamPtr    = (Address)NIL;
  258.         storage.replyParamSize    = 0;
  259.         storage.replyDataPtr    = (Address)NIL;
  260.         storage.replyDataSize    = 0;
  261.         error = (rpcService[command].serviceProc)((ClientData)srvPtr,
  262.                   srvPtr->clientID, command, &storage);
  263.         RPC_SERVICE_TIMING_END(command, &histTime);
  264.  
  265.         if (procPtr->locksHeld != 0) {
  266.         panic("Finished RPC with locks held.\n");
  267.         }
  268.     }
  269.     /*
  270.      * Return an error reply for the stubs.  Note: We could send all
  271.      * replies if the stubs were all changed...
  272.      */
  273.     if (error != SUCCESS && error != RPC_NO_REPLY) {
  274.         Rpc_ErrorReply((ClientData)srvPtr, error);
  275.     }
  276. #ifdef TIMESTAMP
  277.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_OUT, " done");
  278. #endif /* TIMESTAMP */
  279.     }
  280. }
  281.  
  282. /*
  283.  *----------------------------------------------------------------------
  284.  *
  285.  * RpcReclaimServers() --
  286.  *
  287.  *    Spin through the pool of server processes looking for ones to
  288.  *    reclaimed.  A server is eligible for reclaimation if it has been
  289.  *    idle (no new requests from its client) for a given number of
  290.  *    passes over the pool of servers.  It is reclaimed by getting
  291.  *    an explicit acknowledgment from the client and then marking
  292.  *    the server as SRV_FREE.
  293.  *
  294.  *    WARNING: it is possible for this routine to be called very often,
  295.  *    with the daemon being woken up by DAEMON_POKED rather than the
  296.  *    DAEMON_TIMEOUT.  Potentially, this might not give clients enough
  297.  *    time to do an RPC.  This doesn't seem to happen, but we should
  298.  *    change this routine at some point to make sure it can't happen.
  299.  *
  300.  *
  301.  * Results:
  302.  *    None.
  303.  *
  304.  * Side effects:
  305.  *    Age servers, send probes to idle clients, recycle reclaimied servers.
  306.  *    If a client crashes, this routine detects it and reclaims the
  307.  *    server process associated with it and marks the client dead.
  308.  *
  309.  *----------------------------------------------------------------------
  310.  */
  311. ENTRY void
  312. RpcReclaimServers(serversMaxed)
  313.     Boolean serversMaxed;    /* TRUE if the maximum number of servers
  314.                  * have been created.  We reclaim more
  315.                  * quickly if this is set. */
  316. {
  317.     int srvIndex;
  318.     register RpcServerState *srvPtr;
  319.     int (*procPtr)();
  320.     ClientData data = (ClientData) NULL;
  321.  
  322.     for (srvIndex=0 ; srvIndex < rpcNumServers ; srvIndex++) {
  323.     srvPtr = rpcServerPtrPtr[srvIndex];
  324.  
  325.     MASTER_LOCK(&srvPtr->mutex);
  326.  
  327.  
  328.     procPtr = (int (*)())NIL;
  329.     if ((srvPtr->clientID >= 0) &&
  330.         (srvPtr->state & SRV_WAITING)) {
  331.          if (srvPtr->state & SRV_NO_REPLY) {
  332.         /*
  333.          * Reclaim right away if the server process is tied
  334.          * up not replying to a broadcast request.
  335.          */
  336.         procPtr = srvPtr->freeReplyProc;
  337.         data = srvPtr->freeReplyData;
  338.         srvPtr->freeReplyProc = (int (*)())NIL;
  339.         srvPtr->freeReplyData = (ClientData)NIL;
  340.         srvPtr->state = SRV_FREE|SRV_NO_REPLY;
  341.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 5);
  342.         } else if ((srvPtr->state & SRV_AGING) == 0) {
  343.         /*
  344.          * This is the first pass over the server process that
  345.          * has found it idle.  Start it aging.
  346.          */
  347.         srvPtr->state |= SRV_AGING;
  348.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 6);
  349.         srvPtr->age = 1;
  350.         if (serversMaxed) {
  351.             RpcProbe(srvPtr);
  352.         }
  353.         } else {
  354.         /*
  355.          * This process has aged since the last time we looked, maybe
  356.          * sleepTime ago.  We resend to the client with the
  357.          * close flag and continue on.  If RpcServerDispatch gets
  358.          * a reply from the client closing its connection it will
  359.          * mark the server process SRV_FREE.  If we continue to
  360.          * send probes with no reply, we give up after N tries
  361.          * and free up the server.  It is possible that the client
  362.          * has re-allocated its channel, in which case it drops
  363.          * our probes on the floor, or that it has crashed.
  364.          */
  365.         srvPtr->age++;
  366.         if (srvPtr->age >= rpcMaxServerAge) {
  367.             procPtr = srvPtr->freeReplyProc;
  368.             data = srvPtr->freeReplyData;
  369.             srvPtr->freeReplyProc = (int (*)())NIL;
  370.             srvPtr->freeReplyData = (ClientData)NIL;
  371.             rpcSrvStat.reclaims++;
  372.             srvPtr->state = SRV_FREE;
  373.             RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 7);
  374. #ifdef notdef
  375.         } else if (srvPtr->clientID == rpc_SpriteID) {
  376.             printf("Warning: Reclaiming from myself.\n");
  377.             srvPtr->state = SRV_FREE;
  378.             RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 8);
  379. #endif
  380.         } else {
  381.             /*
  382.              * Poke at the client to get a response.
  383.              */
  384.             RpcProbe(srvPtr);
  385.         }
  386.         }
  387.     } else if ((srvPtr->state & SRV_FREE) &&
  388.            (srvPtr->freeReplyProc != (int (*)())NIL)) {
  389.         /*
  390.          * Tidy up after an explicit acknowledgment from a client.
  391.          * This can't be done at interrupt time by ServerDispatch.
  392.          */
  393.         procPtr = srvPtr->freeReplyProc;
  394.         data = srvPtr->freeReplyData;
  395.         srvPtr->freeReplyProc = (int (*)())NIL;
  396.         srvPtr->freeReplyData = (ClientData)NIL;
  397.     }
  398.     MASTER_UNLOCK(&srvPtr->mutex);
  399.     /*
  400.      * Do the call-back to free up resources associated with the last RPC.
  401.      */
  402.     if (procPtr != (int (*)())NIL) {
  403.         (void)(*procPtr)(data);
  404.     }
  405.     }
  406. }
  407.  
  408.  
  409.  
  410. /*
  411.  *----------------------------------------------------------------------
  412.  *
  413.  * NegAckFunc --
  414.  *
  415.  *    Call-back to send a negative acknowledgement so that we won't be at
  416.  *    interrupt level while doing this.
  417.  *
  418.  * Results:
  419.  *    None.
  420.  *
  421.  * Side effects:
  422.  *    A negative ack is output.
  423.  *
  424.  *----------------------------------------------------------------------
  425.  */
  426. static void
  427. NegAckFunc(clientData, callInfoPtr)
  428.     ClientData        clientData;
  429.     Proc_CallInfo    *callInfoPtr;
  430. {
  431.     int            i;
  432.  
  433.     MASTER_LOCK(&(rpcNack.mutex));
  434.     /*
  435.      * We may handle more than one request here.
  436.      */
  437.     for (i = 0; i < rpc_NumNackBuffers; i++) {
  438.     if (rpcNack.hdrState[i] == RPC_NACK_WAITING) {
  439.         rpcNack.hdrState[i] = RPC_NACK_XMITTING;
  440.         rpcNack.rpcHdrArray[i].flags = RPC_NACK | RPC_ACK;
  441.         /*
  442.          * Already did an RpcSrvInitHdr from incoming rpcHdrPtr to our
  443.          * outgoing * buffer in RpcServerDispatch.
  444.          */
  445.         /*
  446.          * This should be okay to do under a masterlock since RpcAck
  447.          * also calls it and it's under a masterlock.
  448.          */
  449.         RpcAddServerTrace((RpcServerState *) NIL, &(rpcNack.rpcHdrArray[i]),
  450.             TRUE, 19);
  451.         rpcSrvStat.nacks++;
  452.         /*
  453.          * Because we pass it the mutex, it will return only when the xmit
  454.          * is done.
  455.          */
  456.         (void) RpcOutput(rpcNack.rpcHdrArray[i].clientID,
  457.             &(rpcNack.rpcHdrArray[i]), &(rpcNack.bufferSet[i]),
  458.             (RpcBufferSet *) NIL, 0,
  459.             (Sync_Semaphore *) &(rpcNack.mutex));
  460.         rpcNack.hdrState[i] = RPC_NACK_FREE;
  461.         rpcNack.numFree++;
  462.     }
  463.     }
  464.     MASTER_UNLOCK(&(rpcNack.mutex));
  465.     return;
  466. }
  467.  
  468.  
  469. /*
  470.  *----------------------------------------------------------------------
  471.  *
  472.  * RpcServerDispatch --
  473.  *
  474.  *      Handle a message sent to a server process.  The client sends (and
  475.  *      re-sends) request messages to the server host.  This routine
  476.  *      handles incoming message accoring to the RPC protocol.  Only new
  477.  *      request messages are passed to the server process.  All other
  478.  *      messages are handled in this routine.
  479.  *
  480.  * Results:
  481.  *    None.
  482.  *
  483.  * Side effects:
  484.  *      The side effects depend on the type of message received.  New
  485.  *      requests are passed off to server processes, client acknowledgments
  486.  *      and retries are processed and discarded.  Unneeded messages are
  487.  *    discarded by returning without copying the message out of the
  488.  *    network buffers.
  489.  *
  490.  *----------------------------------------------------------------------
  491.  */
  492. ENTRY void
  493. RpcServerDispatch(srvPtr, rpcHdrPtr)
  494.     register RpcServerState *srvPtr;    /* The state of the server process */
  495.     register RpcHdr *rpcHdrPtr;        /* The header of the packet as it sits
  496.                      * in the hardware buffers */
  497. {
  498.     register int size;        /* The amount of the data in the message */
  499.     int        i;
  500.     int        foundSpot;    /* Neg ack buf to use. */
  501.     int        alreadyFunc;    /* What buf neg ack function is dealing with. */
  502.  
  503.  
  504.     /*
  505.      * If the server pointer is NIL, this means no server could be allocated
  506.      * and a negative acknowledgement must be issued.
  507.      */
  508.     if (srvPtr == (RpcServerState *) NIL) {
  509.     if (rpcHdrPtr->clientID == rpc_SpriteID) {
  510.         /*
  511.          * Can't nack myself since the network module turns around and
  512.          * reroutes the message and we get deadlock.  Drop the neg ack.
  513.          */
  514.         printf("Can't nack to myself!\n");
  515.         rpcSrvStat.selfNacks++;
  516.         return;
  517.     }
  518.     MASTER_LOCK(&(rpcNack.mutex));
  519.     if (rpc_NumNackBuffers - rpcNack.numFree >
  520.         rpcSrvStat.mostNackBuffers) {
  521.         rpcSrvStat.mostNackBuffers = rpc_NumNackBuffers - rpcNack.numFree;
  522.     }
  523.     if (rpcNack.numFree <= 0) {
  524.         /* Drop the negative ack. */
  525.         MASTER_UNLOCK(&(rpcNack.mutex));
  526.         return;
  527.     }
  528.     /*
  529.      * Copy rpc header info to safe place that won't be freed when
  530.      * we return.
  531.      */
  532.     alreadyFunc = -1;
  533.     foundSpot = -1;
  534.     for (i = 0; i < rpc_NumNackBuffers; i++) {
  535.         /*
  536.          * If we haven't already found a buffer to use and this one is
  537.          * free, use it.
  538.          */
  539.         if (foundSpot == -1 && rpcNack.hdrState[i] == RPC_NACK_FREE) {
  540.         rpcNack.numFree--;
  541.         rpcNack.hdrState[i] = RPC_NACK_WAITING;
  542.         foundSpot = i;
  543.         RpcSrvInitHdr((RpcServerState *) NIL, 
  544.                 &(rpcNack.rpcHdrArray[i]), rpcHdrPtr);
  545.         /*
  546.          * If we've found evidence that there's already a CallFunc for
  547.          * the NegAckFunc, then record the first buffer it will be dealing
  548.          * with next.
  549.          */
  550.         } else if (alreadyFunc == -1 &&
  551.             rpcNack.hdrState[i] == RPC_NACK_WAITING) {
  552.         alreadyFunc = i;
  553.         }
  554.     }
  555.     /*
  556.      * If we've found a buffer and either there's no CallFunc or else it
  557.      * is already past the buffer we've grabbed, then start another
  558.      * CallFunc.
  559.      */
  560.     if (foundSpot != -1 &&
  561.         (alreadyFunc == -1 || alreadyFunc >= foundSpot)) {
  562.         MASTER_UNLOCK(&(rpcNack.mutex));
  563.         Proc_CallFunc(NegAckFunc, (ClientData) NIL, 0);
  564.         return;
  565.     /*
  566.      * Otherwise if we've found a buffer, there's already a CallFunc.
  567.      */
  568.     } else if (foundSpot != -1) {
  569.         MASTER_UNLOCK(&(rpcNack.mutex));
  570.         return;
  571.     }
  572.     MASTER_UNLOCK(&(rpcNack.mutex));
  573.     /*
  574.      * If we haven't found a free buffer, something is wrong.
  575.      */
  576.     panic("RpcServerDispatch: couldn't find free rpcHdr.\n");
  577.     }
  578.  
  579.     /*
  580.      * Acquire the server's mutex for multiprocessor synchronization.  We
  581.      * synchronize with each server process with a mutex that is part of
  582.      * the server's state.
  583.      */
  584.     MASTER_LOCK(&srvPtr->mutex);
  585.     
  586. #ifdef TIMESTAMP
  587.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_a, " server");
  588. #endif /* TIMESTAMP */
  589.     /*
  590.      * Reset aging servers.  This information is maintained by Rpc_Deamon.
  591.      * The reception of a message for the server makes it no longer idle.
  592.      */
  593.     srvPtr->state &= ~SRV_AGING;
  594.     srvPtr->age = 0;
  595.  
  596.     /*
  597.      * If the RPC sequence number is different than the one saved in the
  598.      * server's state then this request signals a new RPC.  We use this as
  599.      * an implicit acknowledgment of the last reply the server sent.  The
  600.      * last transaction ID is saved in the rpc header of our last reply
  601.      * message.
  602.      */
  603.     if (rpcHdrPtr->ID != srvPtr->ID) {
  604.  
  605.     rpcSrvStat.requests++;
  606.     if (srvPtr->state & SRV_WAITING) {
  607.         /*
  608.          * The server has computed a result already so we treat this
  609.          * new request as an implicit acknowledgment of the reply the
  610.          * server sent.  The server process will clean up the previous
  611.          * reply before it starts computing the new reply.
  612.          */
  613.         rpcSrvStat.impAcks++;
  614.         srvPtr->state &= ~SRV_WAITING;
  615.     }
  616.  
  617.     if (srvPtr->state & SRV_FRAGMENT) {
  618.         /*
  619.          * The last send by the client was fragmented but was aborted
  620.          * before we got all the fragments.  Reset the fragment
  621.          * reasembly process.
  622.          */
  623.         rpcSrvStat.fragAborts++;
  624.         srvPtr->state &= ~SRV_FRAGMENT;
  625.         srvPtr->fragsReceived = 0;
  626.     }
  627.  
  628.     if (srvPtr->state & SRV_BUSY) {
  629.         /*
  630.          * The client has abandoned the RPC and started on a new one.
  631.          * This server process may be stuck on some lock, or the
  632.          * client may just be in error.  We mark the server process
  633.          * as STUCK so subsequent requests will not use this server,
  634.          * and the server process will unmark itself when it completes
  635.          * what ever its working on.
  636.          */
  637.         rpcSrvStat.serverBusy++;
  638.         srvPtr->state |= SRV_STUCK;
  639.         goto unlock;
  640.     }
  641.     /*
  642.      * (There should be no bits set in the server's state word.)
  643.      *
  644.      * Update the server's idea of the current transaction.
  645.      */
  646.     srvPtr->ID = rpcHdrPtr->ID;
  647.     /*
  648.      * Reset the true sizes of the two data areas in the arriving message.
  649.      */
  650.     srvPtr->actualDataSize = 0;
  651.     srvPtr->actualParamSize = 0;
  652.     /*
  653.      * Reset our knowledge of what fragments our client has.
  654.      */
  655.     srvPtr->fragsDelivered = 0;
  656.     /*
  657.      * Copy the message from the network's buffers into those of
  658.      * the server process.
  659.      */
  660.     RpcScatter(rpcHdrPtr, &srvPtr->request);
  661.  
  662.     /*
  663.      * Note the actual size of the input information.
  664.      */
  665.     size = rpcHdrPtr->paramSize + rpcHdrPtr->paramOffset;
  666.     if (srvPtr->actualParamSize < size) {
  667.         srvPtr->actualParamSize = size;
  668.     }
  669.     size = rpcHdrPtr->dataSize + rpcHdrPtr->dataOffset;
  670.     if (srvPtr->actualDataSize < size) {
  671.         srvPtr->actualDataSize = size;
  672.     }
  673.     if (rpcHdrPtr->numFrags == 0) {
  674.         /*
  675.          * The message is complete, ie. not fragmented.
  676.          * Return ack if needed and notify the server process.
  677.          */
  678.         srvPtr->fragsReceived = 0;
  679.         if (rpcHdrPtr->flags & RPC_PLSACK) {
  680.         rpcSrvStat.handoffAcks++;
  681.         RpcAck(srvPtr, 0);
  682.         }
  683.         srvPtr->state = SRV_BUSY;
  684. #ifdef WOULD_LIKE
  685.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 2);
  686. #endif WOULD_LIKE
  687.         rpcSrvStat.handoffs++;
  688.         Sync_MasterBroadcast(&srvPtr->waitCondition);
  689.     } else {
  690.         /*
  691.          * The new arrival is only a fragment.
  692.          * Initiate fragment reassembly.  The server process is not
  693.          * notified until the request message is complete.
  694.          */
  695.         rpcSrvStat.fragMsgs++;
  696.         srvPtr->state = SRV_FRAGMENT;
  697.         srvPtr->fragsReceived = rpcHdrPtr->fragMask;
  698.         if (rpcHdrPtr->flags & RPC_PLSACK) {
  699.         rpcSrvStat.fragAcks++;
  700.         RpcAck(srvPtr, RPC_LASTFRAG);
  701.         }
  702.     }
  703. #ifdef TIMESTAMP
  704.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_b, "handoff");
  705. #endif /* TIMESTAMP */
  706.     } else {
  707.     /*
  708.      * This is a message concerning a current RPC.
  709.      */
  710.     if (srvPtr->state & SRV_NO_REPLY) {
  711.         /*
  712.          * The current RPC was a broadcast which we do not want
  713.          * to reply to.  Keep ourselves free - the allocation routine
  714.          * has cleared that state bit.
  715.          */
  716.         srvPtr->state |= SRV_FREE;
  717.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 9);
  718.         rpcSrvStat.discards++;
  719.     } else if (rpcHdrPtr->flags & RPC_ACK) {
  720.         if (rpcHdrPtr->flags & RPC_CLOSE) {
  721.         /*
  722.          * This is an explicit acknowledgment to our reply.
  723.          * Free the server regardless of its state.  The call-back
  724.          * procedure to free resources will be called the next
  725.          * time the server process gets a request, or by Rpc_Daemon.
  726.          */
  727.         rpcSrvStat.closeAcks++;
  728.         srvPtr->state = SRV_FREE;
  729.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 10);
  730.         } else if (rpcHdrPtr->flags & RPC_LASTFRAG) {
  731.         /*
  732.          * This is a partial acknowledgment.  The fragMask field
  733.          * has the summary bitmask of the client which indicates
  734.          * what fragments the client has received.
  735.          */
  736.         rpcSrvStat.recvPartial++;
  737.         srvPtr->fragsDelivered = rpcHdrPtr->fragMask;
  738.         RpcResend(srvPtr);
  739.         } else {
  740.         /*
  741.          * Do nothing. Unknown kind of ack.
  742.          */
  743.         rpcSrvStat.unknownAcks++;
  744.         }
  745.     } else {
  746.         /*
  747.          * Process another fragment or a re-sent request.
  748.          */
  749.         switch(srvPtr->state) {
  750.         default:
  751.             /*
  752.              * oops.  A client is using the same RPC ID that it
  753.              * used with use last (as it crashed, probably).
  754.              * Reset srvPtr->replyRpcHdr.ID so that we can accept
  755.              * new requests from the client.
  756.              */
  757. #ifdef notdef
  758.         printf("Unexpected Server state %x, idx %d, Rpc ID <%x> flags <%x> clientID %d\n",
  759.                 srvPtr->index, srvPtr->state, rpcHdrPtr->ID,
  760.                 rpcHdrPtr->flags, rpcHdrPtr->clientID);
  761. #endif
  762.             rpcSrvStat.badState++;
  763.             srvPtr->replyRpcHdr.ID = 0;
  764.             srvPtr->state = SRV_FREE;
  765.             break;
  766.         case SRV_FREE:
  767.             /*
  768.              * This is an extra packet that has arrived after the
  769.              * client has explicitly acknowledged its reply.
  770.              */
  771.             rpcSrvStat.extra++;
  772.             break;
  773.         case SRV_FRAGMENT:
  774.             /*
  775.              * Sanity check to make sure we expect fragments
  776.              * and then continue fragment reasembly.
  777.              */
  778.             if (rpcHdrPtr->fragMask == 0 ||
  779.             rpcHdrPtr->numFrags == 0) {
  780.             rpcSrvStat.nonFrag++;
  781.             printf("ServerDispatch - got a non-fragment\n");
  782.             break;
  783.             }
  784.             if (srvPtr->fragsReceived & rpcHdrPtr->fragMask) {
  785.             /*
  786.              * Duplicate Fragment.  This ack will return
  787.              * the srvPtr->fragsReceived bitmask to the client.
  788.              */
  789.             rpcSrvStat.dupFrag++;
  790.             RpcAck(srvPtr, RPC_LASTFRAG);
  791.             break;
  792.             } else {
  793.             /*
  794.              * Copy in new fragment and check for completion.
  795.              */
  796.             rpcSrvStat.reassembly++;
  797.             RpcScatter(rpcHdrPtr, &srvPtr->request);
  798.             /*
  799.              * Update actual size information
  800.              */
  801.             size = rpcHdrPtr->paramSize + rpcHdrPtr->paramOffset;
  802.             if (srvPtr->actualParamSize < size) {
  803.                 srvPtr->actualParamSize = size;
  804.             }
  805.             size = rpcHdrPtr->dataSize + rpcHdrPtr->dataOffset;
  806.             if (srvPtr->actualDataSize < size) {
  807.                 srvPtr->actualDataSize = size;
  808.             }
  809.  
  810.             srvPtr->fragsReceived |= rpcHdrPtr->fragMask;
  811.             if (srvPtr->fragsReceived ==
  812.                 rpcCompleteMask[rpcHdrPtr->numFrags]) {
  813.                 srvPtr->state = SRV_BUSY;
  814.                 RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 3);
  815.                 rpcSrvStat.handoffs++;
  816.                 Sync_MasterBroadcast(&srvPtr->waitCondition);
  817.             } else if (rpcHdrPtr->flags & RPC_LASTFRAG) {
  818.                 /*
  819.                  * Incomplete packet after we've gotten
  820.                  * the last fragment in the series.  Partial Ack.
  821.                  */
  822.                 rpcSrvStat.sentPartial++;
  823.                 RpcAck(srvPtr, RPC_LASTFRAG);
  824.             } else {
  825.                 /*
  826.                  * Ignore any "please ack" requests here.  If
  827.                  * the client is resending it will already
  828.                  * trigger a partial ack on every duplicate
  829.                  * fragment we get.
  830.                  */
  831.             }
  832.             }
  833.             break;
  834.         case SRV_BUSY:
  835.             /*
  836.              * We already got this request and the server is busy
  837.              * with it.  We send an explicit acknowledgment to the
  838.              * client to let it know that we successfully got the
  839.              * request.
  840.              */
  841.             rpcSrvStat.busyAcks++;
  842.             RpcAck(srvPtr, 0);
  843.             RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 18);
  844.             break;
  845.         case SRV_WAITING:
  846.             /*
  847.              * The client has dropped our reply, we resend it.
  848.              */
  849.             rpcSrvStat.resends++;
  850.             RpcResend(srvPtr);
  851.             break;
  852.         }
  853.     }
  854. #ifdef TIMESTAMP
  855.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_c, "return");
  856. #endif /* TIMESTAMP */
  857.     }
  858. unlock:
  859.     MASTER_UNLOCK(&srvPtr->mutex);
  860. }
  861.  
  862. /*
  863.  *----------------------------------------------------------------------
  864.  *
  865.  * Rpc_ErrorReply --
  866.  *
  867.  *    Return an error code and an empty reply to a client.
  868.  *
  869.  * Results:
  870.  *    Transmits an error reply to the client host.
  871.  *
  872.  * Side effects:
  873.  *    Send the packet.  Clears the freeReplyProc and Data because
  874.  *    there is an empty reply.
  875.  *
  876.  *----------------------------------------------------------------------
  877.  */
  878. void
  879. Rpc_ErrorReply(srvToken, error)
  880.     ClientData srvToken;        /* Opaque token passed to stub */
  881.     int error;                /* Error code to return to client */
  882. {
  883.     RpcServerState *srvPtr;
  884.     register RpcHdr    *rpcHdrPtr;
  885.     register RpcHdr    *requestHdrPtr;
  886.  
  887.     srvPtr = (RpcServerState *)srvToken;
  888.     rpcHdrPtr = &srvPtr->replyRpcHdr;
  889.     requestHdrPtr = &srvPtr->requestRpcHdr;
  890.  
  891.     srvPtr->freeReplyProc = (int (*)())NIL;
  892.     srvPtr->freeReplyData = (ClientData)NIL;
  893.  
  894.     RpcSrvInitHdr(srvPtr, rpcHdrPtr, requestHdrPtr);
  895.  
  896.     /*
  897.      * Communicate the error code back in the command feild.
  898.      */
  899.     rpcHdrPtr->command = error;
  900.     rpcHdrPtr->flags = RPC_REPLY | RPC_ERROR;
  901.  
  902.     /*
  903.      * Clear sizes in the reply buffers, but not the addresses.
  904.      * This forces a null return and our caller can free the data.
  905.      */
  906.     srvPtr->reply.paramBuffer.length = 0;
  907.     srvPtr->reply.dataBuffer.length = 0;
  908.  
  909.     (void)RpcOutput(rpcHdrPtr->clientID, rpcHdrPtr, &srvPtr->reply,
  910.              (RpcBufferSet *)NIL, 0, (Sync_Semaphore *)NIL);
  911. }
  912.  
  913.  
  914. /*
  915.  *----------------------------------------------------------------------
  916.  *
  917.  * RpcSrvInitHdr --
  918.  *
  919.  *    Initialize the header of a server message from fields
  920.  *    in the clients request message.  This relies on initialization
  921.  *    of unchanging fields inside RpcBufferInit.
  922.  *
  923.  * Results:
  924.  *    None.
  925.  *
  926.  * Side effects:
  927.  *    Addressing and sequencing information from the clients request
  928.  *    message is copeid into the header of a server's outgoing message.
  929.  *
  930.  *----------------------------------------------------------------------
  931.  */
  932. void
  933. RpcSrvInitHdr(srvPtr, rpcHdrPtr, requestHdrPtr)
  934.     RpcServerState    *srvPtr;
  935.     RpcHdr        *rpcHdrPtr;    /* header of outgoing message */
  936.     RpcHdr        *requestHdrPtr;    /* header of client's request */
  937. {
  938.     rpcHdrPtr->serverID = rpc_SpriteID;
  939.     rpcHdrPtr->clientID = requestHdrPtr->clientID;
  940.     rpcHdrPtr->channel = requestHdrPtr->channel;
  941.     rpcHdrPtr->bootID = rpcBootID;
  942.     rpcHdrPtr->ID = requestHdrPtr->ID;
  943.     rpcHdrPtr->numFrags = 0;
  944.     rpcHdrPtr->fragMask = 0;
  945.     rpcHdrPtr->command = requestHdrPtr->command;
  946.     rpcHdrPtr->paramSize = 0;
  947.     rpcHdrPtr->dataSize = 0;
  948.  
  949.     if (srvPtr == (RpcServerState *) NIL) {
  950.     /*
  951.      * If this is a negative ack due to no server proc being available,
  952.      * make sure the serverHint value is reasonable so we don't mess up
  953.      * the client.
  954.      */
  955.     rpcHdrPtr->serverHint = 0;
  956.     }
  957. }
  958.  
  959. /*
  960.  *----------------------------------------------------------------------
  961.  *
  962.  * Rpc_Reply --
  963.  *
  964.  *    Return a reply to a client.
  965.  *
  966.  * Results:
  967.  *    None.
  968.  *
  969.  * Side effects:
  970.  *    Send the reply.
  971.  *
  972.  *----------------------------------------------------------------------
  973.  */
  974. void
  975. Rpc_Reply(srvToken, error, storagePtr, freeReplyProc, freeReplyData)
  976.     ClientData        srvToken;        /* The token for the server
  977.                          * passed to the stub from
  978.                          * the server process */
  979.     int            error;            /* Error code, or SUCCESS */
  980.     register Rpc_Storage *storagePtr;        /* Only the reply fields are
  981.                              * significant. */
  982.     int            (*freeReplyProc) _ARGS_((ClientData freeReplyData));
  983.                         /* Procedure to call to free
  984.                          * up reply state, or NIL */
  985.     ClientData        freeReplyData;        /* Passed to freeReplyProc */
  986. {
  987.     RpcServerState    *srvPtr;
  988.     register RpcHdr    *rpcHdrPtr;
  989.     register RpcHdr    *requestHdrPtr;
  990.  
  991.  
  992.     srvPtr = (RpcServerState *)srvToken;
  993.     rpcHdrPtr = &srvPtr->replyRpcHdr;
  994.     requestHdrPtr = &srvPtr->requestRpcHdr;
  995.  
  996.     /*
  997.      * Set up the call back that will free resources associated
  998.      * with the reply.
  999.      */
  1000.     srvPtr->freeReplyProc = freeReplyProc;
  1001.     srvPtr->freeReplyData = freeReplyData;
  1002.     
  1003.     RpcSrvInitHdr(srvPtr, rpcHdrPtr, requestHdrPtr);
  1004.     rpcHdrPtr->flags = RPC_REPLY;
  1005.     if (error) {
  1006.     /*
  1007.      * Communicate the error code back in the command field.
  1008.      */
  1009.     rpcHdrPtr->command = error;
  1010.     rpcHdrPtr->flags |= RPC_ERROR;
  1011.     }
  1012.  
  1013.     /*
  1014.      * Copy buffer pointers into the server's state.
  1015.      */
  1016.     rpcHdrPtr->paramSize = storagePtr->replyParamSize;
  1017.     srvPtr->reply.paramBuffer.length = storagePtr->replyParamSize;
  1018.     srvPtr->reply.paramBuffer.bufAddr = storagePtr->replyParamPtr;
  1019.  
  1020.     rpcHdrPtr->dataSize = storagePtr->replyDataSize;
  1021.     srvPtr->reply.dataBuffer.length = storagePtr->replyDataSize;
  1022.     srvPtr->reply.dataBuffer.bufAddr = storagePtr->replyDataPtr;
  1023.  
  1024.     (void)RpcOutput(rpcHdrPtr->clientID, rpcHdrPtr, &srvPtr->reply,
  1025.              srvPtr->fragment, 0, (Sync_Semaphore *)NIL);
  1026. }
  1027.  
  1028.  
  1029.  
  1030. /*
  1031.  *----------------------------------------------------------------------
  1032.  *
  1033.  * RpcAck --
  1034.  *
  1035.  *    Return an explicit acknowledgment to a client.
  1036.  *
  1037.  * Results:
  1038.  *    None.
  1039.  *
  1040.  * Side effects:
  1041.  *    None.
  1042.  *
  1043.  *----------------------------------------------------------------------
  1044.  */
  1045. void
  1046. RpcAck(srvPtr, flags)
  1047.     RpcServerState *srvPtr;
  1048.     int flags;
  1049. {
  1050.     RpcHdr    *ackHdrPtr;
  1051.     RpcHdr    *requestHdrPtr;
  1052.  
  1053.     ackHdrPtr = &srvPtr->ackRpcHdr;
  1054.     requestHdrPtr = &srvPtr->requestRpcHdr;
  1055.  
  1056.     ackHdrPtr->flags = flags | RPC_ACK;
  1057.     RpcSrvInitHdr(srvPtr, ackHdrPtr, requestHdrPtr);
  1058.     /*
  1059.      * Let the client know what fragments we have received
  1060.      * so it can optimize retransmission.
  1061.      */
  1062.     ackHdrPtr->fragMask = srvPtr->fragsReceived;
  1063.     /*
  1064.      * Note, can't try ARP here because of it's synchronization with
  1065.      * a master lock and because we are called at interrupt time.
  1066.      */
  1067.     (void)RpcOutput(ackHdrPtr->clientID, ackHdrPtr, &srvPtr->ack,
  1068.              (RpcBufferSet *)NIL, 0, (Sync_Semaphore *)NIL);
  1069. }
  1070.  
  1071. /*
  1072.  *----------------------------------------------------------------------
  1073.  *
  1074.  * RpcResend --
  1075.  *
  1076.  *    Resend a reply to a client.
  1077.  *
  1078.  * Results:
  1079.  *    None.
  1080.  *
  1081.  * Side effects:
  1082.  *    Send the reply.
  1083.  *
  1084.  *----------------------------------------------------------------------
  1085.  */
  1086. void
  1087. RpcResend(srvPtr)
  1088.     RpcServerState    *srvPtr;
  1089. {
  1090.     /*
  1091.      * Consistency check against a service stub that forgot to send a reply.
  1092.      * We can't check sequence numbers because RpcServerDispatch updates the
  1093.      * reply sequence number, but we can verify that the command
  1094.      * in the reply matches the command in the reply.
  1095.      */
  1096.     if ((srvPtr->replyRpcHdr.flags & RPC_ERROR) == 0 &&
  1097.     (srvPtr->replyRpcHdr.command != srvPtr->requestRpcHdr.command)) {
  1098.     printf("RpcResend: RPC %d, client %d, RPC seq # %x, forgot reply?\n",
  1099.         srvPtr->requestRpcHdr.command, srvPtr->requestRpcHdr.clientID,
  1100.         srvPtr->requestRpcHdr.ID);
  1101.     return;
  1102.     }
  1103.     (void)RpcOutput(srvPtr->replyRpcHdr.clientID, &srvPtr->replyRpcHdr,
  1104.                &srvPtr->reply, srvPtr->fragment,
  1105.                srvPtr->fragsDelivered, (Sync_Semaphore *)NIL);
  1106. }
  1107.  
  1108. /*
  1109.  *----------------------------------------------------------------------
  1110.  *
  1111.  * RpcProbe --
  1112.  *
  1113.  *    Send a probe message to the client to see if it is still interested
  1114.  *    in the connection.  The Ack message header/buffer is used for this.
  1115.  *    Synchronization note.  We are called with the srvPtr mutex locked,
  1116.  *    but the server process is not marked BUSY so the dispatcher might
  1117.  *    try to allocate this server.  The mutex prevents this, but it
  1118.  *    is important to not pass the mutex to RpcOutput, which would use
  1119.  *    it to wait for output of the packet.  In that case the mutex is
  1120.  *    released for a while, leaving a window of vulnerability where the
  1121.  *    server could get allocated and the mutex grabbed by the dispatcher.
  1122.  *    By not passing the mutex the packet is sent asynchronously, so there
  1123.  *    is a very remote chance we could try to issue another probe while
  1124.  *    this is still in the output queue.  However, we would be sending
  1125.  *    the same information in the packet, so there shouldn't be a problem.
  1126.  *
  1127.  * Results:
  1128.  *    None.
  1129.  *
  1130.  * Side effects:
  1131.  *    Send the probe message.
  1132.  *
  1133.  *----------------------------------------------------------------------
  1134.  */
  1135. void
  1136. RpcProbe(srvPtr)
  1137.     RpcServerState    *srvPtr;
  1138. {
  1139.     RpcHdr    *ackHdrPtr;
  1140.     RpcHdr    *requestHdrPtr;
  1141.  
  1142.     ackHdrPtr = &srvPtr->ackRpcHdr;
  1143.     requestHdrPtr = &srvPtr->requestRpcHdr;
  1144.  
  1145.     ackHdrPtr->flags = RPC_ACK | RPC_CLOSE;
  1146.     RpcSrvInitHdr(srvPtr, ackHdrPtr, requestHdrPtr);
  1147.  
  1148.     (void)RpcOutput(ackHdrPtr->clientID, ackHdrPtr, &srvPtr->ack,
  1149.              (RpcBufferSet *)NIL, 0, (Sync_Semaphore *)NIL);
  1150. }
  1151.  
  1152.  
  1153. /*
  1154.  *----------------------------------------------------------------------
  1155.  *
  1156.  * RpcAddServerTrace --
  1157.  *
  1158.  *    Add another trace to the list of state tracing for rpc servers.
  1159.  *
  1160.  * Results:
  1161.  *    None.
  1162.  *
  1163.  * Side effects:
  1164.  *    The list is lengthened.
  1165.  *
  1166.  *----------------------------------------------------------------------
  1167.  */
  1168. void
  1169. RpcAddServerTrace(srvPtr, rpcHdrPtr, noneThere, num)
  1170.     RpcServerState    *srvPtr;    /* State to record */
  1171.     RpcHdr         *rpcHdrPtr;    /* The request message header */
  1172.     Boolean        noneThere;    /* No server free */
  1173.     int            num;        /* Which trace */
  1174. {
  1175.     RpcServerStateInfo    *rpcTracePtr;
  1176.  
  1177.     if (!rpcServerTraces.okay) {
  1178.     return;
  1179.     }
  1180.     rpcTracePtr = &(rpcServerTraces.traces[rpcServerTraces.traceIndex]);
  1181.     (void) bzero((Address) rpcTracePtr, sizeof (RpcServerStateInfo));
  1182.     if (!noneThere) {
  1183.     rpcTracePtr->index = srvPtr->index;
  1184.     rpcTracePtr->clientID = srvPtr->clientID;
  1185.     rpcTracePtr->channel = srvPtr->channel;
  1186.     rpcTracePtr->state = srvPtr->state;
  1187.     } else {
  1188.     rpcTracePtr->index = -1;
  1189.     rpcTracePtr->clientID = rpcHdrPtr->clientID;
  1190.     rpcTracePtr->channel = rpcHdrPtr->channel;
  1191.     rpcTracePtr->state = rpcHdrPtr->command;
  1192.     }
  1193.     rpcTracePtr->num = num;
  1194.     Timer_GetCurrentTicks(&rpcTracePtr->time);
  1195.     rpcServerTraces.traceIndex++;
  1196.     if (rpcServerTraces.traceIndex >= RPC_NUM_TRACES) {
  1197.     rpcServerTraces.okay = FALSE;
  1198.     rpcServerTraces.error = TRUE;
  1199.     }
  1200.  
  1201.     return;
  1202. }
  1203.  
  1204.  
  1205. /*
  1206.  *----------------------------------------------------------------------
  1207.  *
  1208.  * Rpc_OkayToTrace --
  1209.  *
  1210.  *    Okay to turn on rpc server state tracing.
  1211.  *
  1212.  * Results:
  1213.  *    None.
  1214.  *
  1215.  * Side effects:
  1216.  *    The tracing is turned on.
  1217.  *
  1218.  *----------------------------------------------------------------------
  1219.  */
  1220. ENTRY void
  1221. Rpc_OkayToTrace(okay)
  1222.     Boolean    okay;
  1223. {
  1224.     MASTER_LOCK(&(rpcServerTraces.mutex));
  1225.     if (okay) {
  1226.     if (!rpcServerTraces.error) {
  1227.         rpcServerTraces.okay = okay;
  1228.     }
  1229.     } else {
  1230.     rpcServerTraces.okay = okay;
  1231.     }
  1232.     MASTER_UNLOCK(&(rpcServerTraces.mutex));
  1233.  
  1234.     return;
  1235. }
  1236.  
  1237.  
  1238. /*
  1239.  *----------------------------------------------------------------------
  1240.  *
  1241.  * Rpc_FreeTraces --
  1242.  *
  1243.  *    If memory allocation is involved, free up the space used by the rpc
  1244.  *    server tracing.  Otherwise, just reinitialize it.
  1245.  *
  1246.  * Results:
  1247.  *    None.
  1248.  *
  1249.  * Side effects:
  1250.  *    Tracing is turned off and some reinitialization is done.
  1251.  *
  1252.  *----------------------------------------------------------------------
  1253.  */
  1254. ENTRY void
  1255. Rpc_FreeTraces()
  1256. {
  1257.     MASTER_LOCK(&(rpcServerTraces.mutex));
  1258.     rpcServerTraces.okay = FALSE;
  1259.  
  1260.     rpcServerTraces.traceIndex = 0;
  1261.     rpcServerTraces.error = FALSE;
  1262.  
  1263.     MASTER_UNLOCK(&(rpcServerTraces.mutex));
  1264.     return;
  1265. }
  1266.  
  1267.  
  1268. /*
  1269.  *----------------------------------------------------------------------
  1270.  *
  1271.  * Rpc_DumpServerTraces --
  1272.  *
  1273.  *    Dump the server traces into a buffer for the user.
  1274.  *
  1275.  * Results:
  1276.  *    Failure if something goes wrong.  Success otherwise.
  1277.  *
  1278.  * Side effects:
  1279.  *    The trace info is copied into a buffer.  Size of needed buffer is
  1280.  *    also copied out.
  1281.  *
  1282.  *----------------------------------------------------------------------
  1283.  */
  1284. ENTRY ReturnStatus
  1285. Rpc_DumpServerTraces(length, resultPtr, lengthNeededPtr)
  1286.     int                     length;         /* size of data buffer */
  1287.     RpcServerUserStateInfo    *resultPtr;    /* Array of info structs. */
  1288.     int                     *lengthNeededPtr;/* to return space needed */
  1289.  
  1290. {
  1291.     RpcServerUserStateInfo    *infoPtr;
  1292.     RpcServerStateInfo        *itemPtr;
  1293.     int                numNeeded;
  1294.     int                numAvail;
  1295.     int                i;
  1296.  
  1297.     MASTER_LOCK(&(rpcServerTraces.mutex));
  1298.     if (rpcServerTraces.traceIndex <= 0) {
  1299.     MASTER_UNLOCK(&(rpcServerTraces.mutex));
  1300.     return FAILURE;
  1301.     }
  1302.     if (resultPtr != (RpcServerUserStateInfo *) NIL) {
  1303.     bzero((char *) resultPtr, length);
  1304.     }
  1305.     numNeeded = 0;
  1306.     numAvail = length / sizeof (RpcServerUserStateInfo);
  1307.  
  1308.     infoPtr = resultPtr;
  1309.     for (i = 0; i < rpcServerTraces.traceIndex; i++) {
  1310.     itemPtr = &(rpcServerTraces.traces[i]);
  1311.     numNeeded++;
  1312.     if (numNeeded > numAvail) {
  1313.         continue;
  1314.     }
  1315.     infoPtr->index = itemPtr->index;
  1316.     infoPtr->clientID = itemPtr->clientID;
  1317.     infoPtr->channel = itemPtr->channel;
  1318.     infoPtr->state = itemPtr->state;
  1319.     infoPtr->num = itemPtr->num;
  1320.     Timer_GetRealTimeFromTicks(itemPtr->time, &(infoPtr->time), 
  1321.                 (int *) NIL, (Boolean *) NIL);
  1322.     infoPtr++;
  1323.     }
  1324.     *lengthNeededPtr = numNeeded * sizeof (RpcServerUserStateInfo);
  1325.  
  1326.     MASTER_UNLOCK(&(rpcServerTraces.mutex));
  1327.     return SUCCESS;
  1328. }
  1329.  
  1330. void
  1331. RpcInitServerTraces()
  1332. {
  1333.     rpcServerTraces.traces = (RpcServerStateInfo *) malloc(RPC_NUM_TRACES *
  1334.                         sizeof (RpcServerStateInfo));
  1335.     return;
  1336. }
  1337.  
  1338.  
  1339.  
  1340. /*
  1341.  *----------------------------------------------------------------------
  1342.  *
  1343.  * RpcSetNackBufs --
  1344.  *
  1345.  *    Allocate and set up the correct number of nack buffers.
  1346.  *
  1347.  * Results:
  1348.  *    None.
  1349.  *
  1350.  * Side effects:
  1351.  *    Some freeing and malloc'ing.
  1352.  *
  1353.  *----------------------------------------------------------------------
  1354.  */
  1355. void
  1356. RpcSetNackBufs()
  1357. {
  1358.     int    i;
  1359.  
  1360.     if (oldNumNackBuffers == rpc_NumNackBuffers) {
  1361.     /* Nothing to do, initialized already. */
  1362.     return;
  1363.     }
  1364.     if (rpcServiceEnabled) {
  1365.     /* Cannot change nack buffers once service is enabled, for now. */
  1366.     return;
  1367.     }
  1368.     /* Free old nack buffers if there were any. */
  1369.     if (oldNumNackBuffers > 0 && rpcNack.rpcHdrArray != (RpcHdr *) NIL) {
  1370.     free((char *) rpcNack.rpcHdrArray);
  1371.     free((char *) rpcNack.hdrState);
  1372.     free((char *) rpcNack.bufferSet);
  1373.     /*
  1374.      * Note, this won't free up all the buffer stuff since
  1375.      * RpcBufferInit calls Vm_RawAlloc instead of malloc.
  1376.      */
  1377.     }
  1378.     /* Allocate new nack buffers. */
  1379.     rpcNack.rpcHdrArray = (RpcHdr *) malloc(rpc_NumNackBuffers *
  1380.         sizeof (RpcHdr));
  1381.     rpcNack.hdrState = (int *) malloc(rpc_NumNackBuffers * sizeof (int));
  1382.  
  1383.     rpcNack.bufferSet = (RpcBufferSet *) malloc(rpc_NumNackBuffers *
  1384.             sizeof (RpcBufferSet));
  1385.  
  1386.     for (i = 0; i < rpc_NumNackBuffers; i++) {
  1387.         rpcNack.hdrState[i] = RPC_NACK_FREE;
  1388.         RpcBufferInit(&(rpcNack.rpcHdrArray[i]),
  1389.                 &(rpcNack.bufferSet[i]), -1, -1);
  1390.     }
  1391.     /* set old to new */
  1392.     rpcNack.numFree = rpc_NumNackBuffers;
  1393.     oldNumNackBuffers = rpc_NumNackBuffers;
  1394.  
  1395.     return;
  1396. }
  1397.